package com.engine4cloud.tdf.education.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.engine4cloud.tdf.common.data.web.query.Pages;
import com.engine4cloud.tdf.common.data.web.query.Queries;
import com.engine4cloud.tdf.common.data.web.response.PageInfo;
import com.engine4cloud.tdf.common.data.web.response.Params;
import com.engine4cloud.tdf.common.security.service.TdfUser;
import com.engine4cloud.tdf.common.security.util.SecurityUtils;
import com.engine4cloud.tdf.education.convert.EduStudentConvert;
import com.engine4cloud.tdf.education.dto.query.EduStudentQueryDTO;
import com.engine4cloud.tdf.education.dto.query.EduStudentTaskQueryDTO;
import com.engine4cloud.tdf.education.dto.result.EduStudentCourseResultDTO;
import com.engine4cloud.tdf.education.dto.result.EduStudentResultDTO;
import com.engine4cloud.tdf.education.dto.EduStudentDTO;
import com.engine4cloud.tdf.education.entity.EduStudentEntity;
import com.engine4cloud.tdf.education.mapper.EduStudentMapper;
import com.engine4cloud.tdf.education.service.EduStudentService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 学员
 *
 * @author wenjie
 * @date 2024-07-30 14:59:31
 */
@Service
public class EduStudentServiceImpl extends ServiceImpl<EduStudentMapper, EduStudentEntity> implements EduStudentService {
    @Override
    public PageInfo<EduStudentResultDTO> pageList(Params pageable, EduStudentQueryDTO dto) {
        IPage<EduStudentEntity> page = super.page(Pages.page(pageable), wrapper(dto));
        return Pages.convert(page, EduStudentConvert.INSTANCE::convert);
    }

    @Override
    public PageInfo<EduStudentCourseResultDTO> pageList(Params pageable, EduStudentTaskQueryDTO dto) {
        return Pages.convert(this.baseMapper.pageList(Pages.page(pageable), dto));
    }

    @Override
    public EduStudentResultDTO getById(Long id) {
        return EduStudentConvert.INSTANCE.convert(super.getById(id));
    }

    @Override
    public List<EduStudentResultDTO> findList(String groupCode) {
        return super.list(wrapper(new EduStudentQueryDTO(groupCode))).stream().map(EduStudentConvert.INSTANCE::convert).toList();
    }

    @Override
    public List<EduStudentResultDTO> findMutList(List<String> groupCode) {
        LambdaQueryWrapper<EduStudentEntity> wrapper = Queries.lambda();
        Queries.accept(groupCode, v -> wrapper.in(EduStudentEntity::getGroupCode, v));
        return super.list(wrapper).stream().map(EduStudentConvert.INSTANCE::convert).toList();
    }

    @Override
    public void batchCreate(String groupCode, List<EduStudentDTO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        TdfUser user = SecurityUtils.getUser();
        super.saveBatch(list.stream().map(s -> EduStudentConvert.INSTANCE.create(groupCode, s, user.getTenantId())).toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdate(String groupCode, List<EduStudentDTO> studentList) {
        List<EduStudentResultDTO> existedList = this.findList(groupCode);

        List<EduStudentEntity> preSaveList = this.preSaveList(groupCode, existedList, studentList);
        if (CollectionUtils.isNotEmpty(preSaveList)) {
            super.saveBatch(preSaveList);
        }

        List<Long> preDeleteList = this.preDeleteList(studentList, existedList);
        if (CollectionUtils.isNotEmpty(preDeleteList)) {
            super.removeBatchByIds(preDeleteList);
        }
    }

    private List<EduStudentEntity> preSaveList(String groupCode, List<EduStudentResultDTO> existedList, List<EduStudentDTO> studentList) {
        if (CollectionUtils.isEmpty(studentList)) {
            return Collections.emptyList();
        }

        TdfUser user = SecurityUtils.getUser();
        Map<String, EduStudentResultDTO> existMap = existedList.stream().collect(Collectors.toMap(EduStudentResultDTO::getCode, Function.identity(), (v1, v2) -> v1));
        return studentList.stream().filter(a -> !existMap.containsKey(a.getCode())).map(a -> EduStudentConvert.INSTANCE.create(groupCode, a, user.getTenantId())).toList();
    }

    private List<Long> preDeleteList(List<EduStudentDTO> studentList, List<EduStudentResultDTO> existedList) {
        if (CollectionUtils.isEmpty(existedList)) {
            return Collections.emptyList();
        }


        Map<String, EduStudentDTO> modelMap = studentList.stream().collect(Collectors.toMap(EduStudentDTO::getCode, Function.identity(), (v1, v2) -> v1));
        return existedList.stream().filter(e -> !modelMap.containsKey(e.getCode())).map(EduStudentResultDTO::getId).toList();
    }

    private LambdaQueryWrapper<EduStudentEntity> wrapper(EduStudentQueryDTO query) {
        LambdaQueryWrapper<EduStudentEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(EduStudentEntity::getId, v));
        Queries.accept(query.getGroupCode(), v -> wrapper.eq(EduStudentEntity::getGroupCode, v));
        Queries.accept(query.getCode(), v -> wrapper.eq(EduStudentEntity::getCode, v));
        Queries.accept(query.getName(), v -> wrapper.like(EduStudentEntity::getName, v));
        return wrapper;
    }
}